import {saveAs} from 'file-saver'
import * as ExcelJs from 'exceljs'
import {Workbook, Worksheet, Row, Cell} from 'exceljs'
import JsZip from 'jszip'

// 默认的列宽
export const DEFAULT_COLUMN_WIDTH = 20;
// 默认行高
export const DEFAULT_ROW_HEIGHT = 20;

// 导出多个文件为zip的压缩包
export async function downloadFilesZip(params){
  const zip = new JsZip()
  // 待每个文件都写入完成之后再生成 zip 文件
  // ?. 可选链操作符 用于判断对象的某个属性是否存在，如果存在那么就返回整个属性的值，否则返回undefined
  const promises = params?.files?.map(async (param) => await handleEachFile(param,zip,''))
  // 等待所有的请求都完成
  await Promise.all(promises)
  // 在当前的文件夹级别生成一个完整的Zip文件
  zip.generateAsync({type: 'blob'})
    .then(blob =>{
      saveAs(blob, `${params.zipName}.zip`)
    })
}

// 导出多级文件夹的压缩包
export async function downloadFilesWithFolder(params){
  const zip = new JsZip()
  const outPromises = params?.folder?.map(async folder => await handleFolder(zip, folder))
  await Promise.all(outPromises)
  zip.generateAsync({type: 'blob'})
    .then(blob =>{
      saveAs(blob, `${params.zipName}.zip`)
    })
}

// 生成多级文件夹
async function handleFolder(zip, folder){
  const folderPromises = []
  const promises = folder?.files?.map(async param => await handleEachFile(param, zip, folder.folderName))
  await Promise.all([...promises, ...folderPromises])
}


// 生成excel文件
async function handleEachFile(param, zip, folderName){
  // 创建工作簿
  const workbook = new ExcelJs.Workbook()
  param?.sheets?.forEach((sheet) => handleEachSheet(workbook, sheet))
  // 生成blob
  const data = await workbook.xlsx.writeBuffer()
  const blob = new Blob([data], {type: ''})
  if(folderName){
    // folder() 创建一个不存在的目录，返回一个新的JSZip对象，新文件夹作为根目录
    // file() 取得带有指定名称的文件
    zip.folder(folderName)?.file(`${param.filename}.xlsx`, blob)
  }else{
    // 写入 zip 中一个文件
    zip.file(`${param.filename}.xlsx`, blob)
  }
}

// 添加工作表
export function handleEachSheet(workbook, sheet){
  // 添加sheet
  const worksheet = workbook.addWorksheet(sheet.sheetName)
  // 设置 sheet 的默认行高。设置默认行高与自定撑开单元格有冲突
  // worksheet.properties.defaultRowHeight = 20
  // 设置列
  worksheet.columns = generateHeaders(sheet.columns)
  handleDataWithRender(worksheet, sheet)
}

// 根据 antd 的 column 生成 exceljs 的 column
export function generateHeaders(columns){
  return columns?.map((col) =>{
    const obj = {
      // 显示的name
      header: col.label,
      // 用于数据匹配的key
      key: col.name,
      // 列宽
      width: col.width / 5 > DEFAULT_COLUMN_WIDTH ? col.width / 5 : DEFAULT_COLUMN_WIDTH,
    }
    if(col.children){
      obj.children = col.children?.map((item) =>({
        key: item.name,
        header: item.label,
        width: item.width,
        parentKey: col.name
      }))
    }
    return obj
  })
}

// 如果 column 有 render 函数，则以 render 渲染的结果显示
function handleDataWithRender(worksheet, sheet){
  const {dataSource, columns} = sheet
  const rowsData = dataSource?.map(data =>{
    return columns?.map(column =>{
      const renderResult = column?.render?.(data[column.name],data)
      if(renderResult){
        // 如果不是 object ,说明没有包裹标签，是基本类型，则直接返回
        if(typeof renderResult != 'object'){
          return renderResult
        }
        // 如果是 object ,说明包裹了标签，逐级取出值
        return getValueFromRender(renderResult)
      }
      return data[column.name]
    })
  })
  // 添加行
  const rows = worksheet.addRows(rowsData)
  // 设置每行的样式
  addStyleToData(rows)
}

// 递归取出 render 里的值
function getValueFromRender(renderResult){
  if(renderResult?.type){
    const children = renderResult?.props?.children
    if(children?.type){
      return getValueFromRender(children)
    }else{
      return children
    }
  }
  return ''
}

// 设置行样式
function addStyleToData(rows){
  rows?.forEach((row) =>{
    // 设置字体
    row.font = {
      size: 11,
      name: '微软雅黑',
    }
    // 设置对齐方式
    row.alignment = {
      vertical: 'middle',
      horizontal: 'left',
      wrapText: true,
    }
  })
}
